package org.apache.sad.core.framework.jaxrpc;

import java.net.SocketTimeoutException;
import java.rmi.RemoteException;

import javax.xml.rpc.Stub;
import javax.xml.rpc.soap.SOAPFaultException;

import org.apache.sad.core.framework.exception.BaseException;
import org.apache.sad.core.framework.exception.ConnectionTimeoutException;
import org.apache.sad.core.framework.exception.ReadTimeoutException;
import org.apache.sad.core.framework.exception.SystemException;
import org.apache.sad.core.framework.utils.ExceptionUtil;

/**
 * You only need to specify one of the following one properties.
 * <ul>
 * <li>serviceInterface</li>
 * </ul>
 *
 * connectionTimeout and readTimeout are optional.
 *
 */
public class Wl92JaxRpcRuntime extends JaxRpcRuntimeBase {

	private final static String CONNECTION_TIMEOUT = "weblogic.wsee.transport.connection.timeout";

	private final static String READ_TIMEOUT = "weblogic.wsee.transport.read.timeout";

    /**
     * Use reflection to get the port. This is WebLogic9.2 specific because calling
     * getPort() on their serviceImpl will return a proxy which is not what we
     * want. Otherwise the documentwrapped method is called.
     *
     * @param portName
     * @return
     */
    protected String getMethodName(String portName) {
       StringBuffer sb = new StringBuffer(GET);
       if (Character.isLowerCase(portName.charAt(0))) {
           sb.append(Character.toUpperCase(portName.charAt(0)));
           if (portName.length() > 1) {
               sb.append(portName.substring(1));
           }
       } else {
           sb.append(portName);
       }

       return sb.toString();
    }

    public Throwable handleRemoteException(RemoteException e) {
        SOAPFaultException soapFault = null;

        // stub client
        Throwable cause = e.getCause();

        if (cause instanceof SOAPFaultException) {
            soapFault = (SOAPFaultException) cause;

        	try
        	{
        		BaseException baseEx = BaseException.fromSOAPFault(soapFault);
        		if (baseEx.getMessages().length > 0) {
        			return baseEx;
        		}
        		else {
        			log.info("No Messages present in the SoapFaultException");
        		}
        	}
        	catch (Exception ex) {
        		log.info("Unable to transform SoapFault Exception", ex);
        	}
		}

        if (soapFault != null) {
        	Throwable rootCause = ExceptionUtil.getRootCause(soapFault);
        	if ( rootCause instanceof SocketTimeoutException ) {
        		if ( rootCause.getMessage().contains("Read timed out") ) {
        			throw new ReadTimeoutException("Failed to invoke remote web service, read timed out.");
        		} else {
        			throw new ConnectionTimeoutException("Failed to invoke remote web service, connect timed out.");
        		}
        	} else {
        		return new SystemException("Failed to invoke remote web service. Fault code: " + soapFault.getFaultCode().getLocalPart() + ", fault string: " + soapFault.getFaultString());
        	}
        } else {
        	return new SystemException("Failed to invoke remote web service");
        }
    }

	public void setConnectionTimeout(Stub stub, Integer timeoutInMilliSeconds) {
		if (timeoutInMilliSeconds != null) {
			stub._setProperty(CONNECTION_TIMEOUT, timeoutInMilliSeconds);
		}
	}

	public void setReadTimeout(Stub stub, Integer timeoutInMilliSeconds) {
		if (timeoutInMilliSeconds != null) {
			stub._setProperty(READ_TIMEOUT, timeoutInMilliSeconds);
		}
	}
}
